﻿// -----------------------------------------------------------------------------
// Native Object extensions

Number.prototype.map = function (istart, istop, ostart, ostop) {
  return ostart + (ostop - ostart) * ((this - istart) / (istop - istart));
};

Number.prototype.limit = function (min, max) {
  return Math.min(max, Math.max(min, this));
};

Number.prototype.round = function (precision) {
  precision = Math.pow(10, precision || 0);
  return Math.round(this * precision) / precision;
};

Number.prototype.floor = function () {
  return Math.floor(this);
};

Number.prototype.ceil = function () {
  return Math.ceil(this);
};

Number.prototype.toInt = function () {
  return (this | 0);
};

Array.prototype.erase = function (item) {
  for (var i = this.length; i--; ) {
    if (this[i] === item) {
      this.splice(i, 1);
    }
  }
  return this;
};

Array.prototype.random = function () {
  return this[Math.floor(Math.random() * this.length)];
};

Function.prototype.bind = function (bind) {
  var self = this;
  return function () {
    var args = Array.prototype.slice.call(arguments);
    return self.apply(bind || null, args);
  };
};

Object.extend = function (destination, source) {
  for (var property in source)
    destination[property] = source[property];
  return destination;
};

function loadScript(url, async) {
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = url;
  script.async = async;
  document.head.appendChild(script);
}

// -----------------------------------------------------------------------------
// Class object based on John Resigs code; inspired by base2 and Prototype
// http://ejohn.org/blog/simple-javascript-inheritance/

var initializing = false, fnTest = /xyz/.test(function () { xyz; }) ? /\bparent\b/ : /.*/;
var Eg = {
  ready: false,
  $new: function (name) {
    return document.createElement(name);
  },
  copy: function (object) {
    if (!object || typeof (object) != 'object' || object instanceof HTMLElement || object instanceof Eg.Class) {
      return object;
    }
    else if (object instanceof Array) {
      var c = [];
      for (var i = 0, l = object.length; i < l; i++) {
        c[i] = Eg.copy(object[i]);
      }
      return c;
    }
    else {
      var c = {};
      for (var i in object) {
        c[i] = Eg.copy(object[i]);
      }
      return c;
    }
  },


  merge: function (original, extended) {
    for (var key in extended) {
      var ext = extended[key];
      if (typeof (ext) != 'object' || ext instanceof HTMLElement || ext instanceof Eg.Class) {
        original[key] = ext;
      }
      else {
        if (!original[key] || typeof (original[key]) != 'object') {
          original[key] = (ext instanceof Array) ? [] : {};
        }
        Eg.merge(original[key], ext);
      }
    }
    return original;
  },

  keysort: function (obj) {
    if (!obj || typeof (obj) != 'object') {
      return [];
    }

    var keys = [], values = [];
    for (var i in obj) {
      keys.push(i);
    }

    keys.sort();
    for (var i = 0; i < keys.length; i++) {
      values.push(obj[keys[i]]);
    }

    return values;
  }
};
Eg.Class = function () { };
var inject = function (prop) {
  var proto = this.prototype;
  var parent = {};
  for (var name in prop) {
    if (typeof (prop[name]) == "function" && typeof (proto[name]) == "function" && fnTest.test(prop[name])) {
      parent[name] = proto[name]; // save original function
      proto[name] = (function (name, fn) {
        return function () {
          var tmp = this.parent;
          this.parent = parent[name];
          var ret = fn.apply(this, arguments);
          this.parent = tmp;
          return ret;
        };
      })(name, prop[name]);
    }
    else {
      proto[name] = prop[name];
    }
  }
};

Eg.Class.extend = function (prop) {
  var parent = this.prototype;

  initializing = true;
  var prototype = new this();
  initializing = false;

  for (var name in prop) {
    if(typeof (prop[name]) == "function" && typeof (parent[name]) == "function" && fnTest.test(prop[name])) {
      prototype[name] = (function (name, fn) {
        return function () {
          var tmp = this.parent;
          this.parent = parent[name];
          var ret = fn.apply(this, arguments);
          this.parent = tmp;
          return ret;
        };
      })(name, prop[name]);
    }
    else {
      prototype[name] = prop[name];
    }
  }

  function Class() {
    if (!initializing) {

      // If this class has a staticInstantiate method, invoke it
      // and check if we got something back. If not, the normal
      // constructor (init) is called.
      if (this.staticInstantiate) {
        var obj = this.staticInstantiate.apply(this, arguments);
        if (obj) {
          return obj;
        }
      }
      for (var p in this) {
        if (typeof (this[p]) == 'object') {
          this[p] = Eg.copy(this[p]); // deep copy!
        }
      }
      if (this.init) {
        this.init.apply(this, arguments);
      }
    }
    return this;
  }

  Class.prototype = prototype;
  Class.constructor = Class;
  Class.extend = arguments.callee;
  Class.inject = inject;

  return Class;
};
